/**
 * 1. promise 是一个类
 * 2. 创建promise对象时需要传入承诺的逻辑（执行器），该执行器立即执行=》constructor中接受一个函数，且该函数在constructor中会立即执行
 * 3. 执行器中传入两个参数，resolve及reject，用来在承诺逻辑中根据成功及失败的逻辑改变promise中的状态
 * 4. Promise 中的三种状态： 成功 fulfilled 失败 rejected 等待 pending
 * 5. 执行器中的resolve函数及reject函数用来修改状态，状态只能由pending变为fulfilled或rejected
 * 6. resolve及reject可接收参数，表示成功的值及错误信息
 * 7. promise的then函数接受两个参数，第一个函数为成功回调，第二个为失败回调，当状态为fulfilled调用成功回调，当状态为rejected调用失败回调，当状态为pending时，保存当前成功及失败回调，在执行resolve及reject时再执行回调，当不传入回调时返回上一个then中的成功及失败结果
 * 8. then的回调方法中接收参数，参数为当前promise对象中的成功的值及错误信息
 * 9. then方法返回一个promise对象，支持链式调用
 * 10. then方法将当前回调操作的结果值作为参数传递给下一个then方法=》通过调用返回的promise对象的resolve方法，可在下一个then中接收返回值
 * 11. 若then的回调函数执行返回一个普通值，可直接调用resolve， 如果返回一个promise对象则调用then方法并传入resolve及reject,执行完该promise后再调用resolve及reject
 * 12. 若then函数返回的promise对象即是自己，给出错误提示
 * 13. all静态方法，接受数组，返回promise，若数组中的当前值是普通值，直接加入返回数组，若是promise对象，执行该对象的then方法，若成功，成功回调函数内将结果放入数组，若失败，直接返回错误
 * 14. resolve静态方法， 接受参数，返回一个promise对象， 若参数为promise对象，直接返回，若参数为普通值，返回新的promise对象，并resolve当前值
 * 15. finally方法，接收回调函数作为参数，无论成功失败，最终都执行该回调函数，并返回一个promise对象
 * 16. race静态方法，接收数组作为参数，无论成功或失败，哪个先执行完就返回结果
 * 
 */
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败

 class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject) //2.立即执行执行器
        } catch (e) {
            this.reject(e);
        }
       
    }
    status = PENDING;//状态
    value = undefined;//成功的值
    reason = undefined;//失败原因
    successCallback = [];// then调用时pengding状态保存的成功回调
    failCallback = [];// then调用时pengding状态保存的失败回调

    resolve = value => {
        if (this.status !== PENDING) return;//5.只能由pending变为fulfilled
        this.status = FULFILLED;//5.将状态由pending变为fulfilled
        this.value = value;//6.保存成功的值
        while(this.successCallback.length) this.successCallback.shift()()//7. 对then执行中pengding保存的成功回调调用
    }

    reject = reason => {
        if (this.status !== PENDING) return;//5.只能由pending变为rejected
        this.status = REJECTED;//5.将状态由pending变为rejected
        this.reason = reason; //6.保存失败后的原因
        while(this.failCallback.length) this.failCallback.shift()()//7. 对then执行中pengding保存的失败回调调用
    }

    then(successCallback, failCallback) {
        successCallback = successCallback ? successCallback : value => value;//7.当不传入回调时返回上一个then中的成功结果
        failCallback = failCallback ? failCallback: reason => { throw reason };//7.当不传入回调时返回上一个then中的失败结果
        let promise2 = new MyPromise((resolve, reject) => {//9. 返回promise对象
            if (this.status === FULFILLED) {//7.当状态为fulfilled调用成功回调
                setTimeout(() => {//setTimeout保证当前promise2对象已创建
                    try {
                        let x = successCallback(this.value);//8.then的回调方法中接收参数，参数为当前promise对象中的成功的值
                        resolvePromise(promise2, x, resolve, reject)//7. 调用成功回调，x为成功回调后的结果值
                    }catch (e) {
                        reject(e);
                    }
                }, 0)
            } else if (this.status === REJECTED) {//7.当状态为rejected调用失败回调
                setTimeout(() => {//setTimeout保证当前promise2对象已创建
                    try {
                        let x = failCallback(this.reason);//8.then的回调方法中接收参数，参数为当前promise对象中的错误信息
                        resolvePromise(promise2, x, resolve, reject)//7. 调用失败回调，x为失败回调后的结果值
                    }catch (e) {
                    reject(e);
                    }
                }, 0)
            } else {//7.当状态为pending时，保存当前成功及失败回调，在执行resolve及reject时再执行回调
                this.successCallback.push(() => {//7. 保存当前成功回调，在执行resolve时再执行回调
                    setTimeout(() => {//setTimeout保证当前promise2对象已创建
                    try {
                        let x = successCallback(this.value);
                        resolvePromise(promise2, x, resolve, reject)
                    }catch (e) {
                        reject(e);
                    }
                    }, 0)
                });
                this.failCallback.push(() => {//7. 保存当前失败回调，在执行reject时再执行回调
                    setTimeout(() => {
                    try {
                        let x = failCallback(this.reason);
                        resolvePromise(promise2, x, resolve, reject)
                    }catch (e) {
                        reject(e);
                    }
                    }, 0)
                });
                
            }
        })
        return promise2;
    }

    finally (callback) {
        return this.then(value => {//调用then，执行完成后，调用resolve执行参数的callback
            return MyPromise.resolve(callback()).then(() => value);
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason })
        })
    }

    catch (failCallback) {//调用then，传递失败回调
        return this.then(undefined, failCallback)
    }

    static all (array) {
        let result = [];
        let index = 0;
        return new MyPromise((resolve, reject) => {//13. 返回promise
            function addData (key, value) {//key及value保证顺序一致
                result[key] = value;
                index++;
                if (index === array.length) {
                    resolve(result)//全部处理完成后resolve
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {//若数组中的当前值是promise对象，执行该对象的then方法，若成功，成功回调函数内将结果放入数组，若失败，直接返回错误
                    current.then(value => addData(i, value), reason => reject(reason))
                }else {//13. 若数组中的当前值是普通值，直接加入返回数组
                    addData(i, array[i]);
                }
            }
        })
    }

    static race (array) {//16. race静态方法，接收数组作为参数，无论成功或失败，哪个先执行完就返回结果
        let result = [];
        let index = 0;
        return new MyPromise((resolve, reject) => {//返回promise
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {//若数组中的当前值是promise对象，执行该对象的then方法，若成功，直接resolve, 若失败直接reject，
                    current.then(value => resolve(value), reason => reject(reason))
                }else {//13. 若数组中的当前值是普通值，直接返回
                    resolve(current)
                }
            }
        })
    }

    static resolve (value) {//14. resolve静态方法， 接受参数，返回一个promise对象
        if (value instanceof MyPromise) return value;//若参数为promise对象，直接返回
        return new MyPromise(resolve => resolve(value));//若参数为普通值，返回新的promise对象，并resolve当前值
    }
    
 }

 function resolvePromise (promise2, x, resolve, reject) {
    if (promise2 === x) {//12. 若then函数返回的promise对象即是自己，给出错误提示
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if (x instanceof MyPromise) {//11. 若then的回调函数返回一个promise对象，则调用then方法并传入resolve及reject,执行完该promise后再调用resolve及reject
        x.then(resolve, reject);
    } else {//11. 若then的回调函数执行返回一个普通值，可直接调用resolve
        resolve(x);
    }
}

let p1 = new MyPromise(function (resolve, reject) {
        setTimeout(function () {
            resolve('p1成功')
        }, 2000)
    })

let p2 = new MyPromise(function (resolve, reject) {
        setTimeout(function () {
            reject('p2失败')
        }, 1000)
    })

MyPromise.race([p1,p2]).then((result) => console.log(result)).catch(err => console.log(err))
  
